import 'dart:async';
import 'package:flutter_09_game/utils/log/utils_log.dart';
import 'package:web_socket_channel/io.dart';
import 'package:web_socket_channel/status.dart' as status;
import 'package:web_socket_channel/web_socket_channel.dart';

/// WebSocket连接检测工具类
/// 提供WebSocket连接可用性检测功能
class WebSocketChecker {
  /// 检测传入的WebSocket地址哪些可用
  /// [urls] 需要检测的WebSocket地址列表
  /// [timeout] 单个连接检测的超时时间，默认5秒
  /// 返回可用的WebSocket地址列表
  static Future<List<String>> checkAvailableWebSockets(
    List<String> urls, {
    Duration? timeout,
  }) async {
    if (urls.isEmpty) return [];

    final Duration checkTimeout = timeout ?? const Duration(seconds: 3);

    // 并发检测所有WebSocket地址
    final List<Future<String?>> futures = urls.map((url) {
      return _checkSingleWebSocket(url, timeout: checkTimeout);
    }).toList();

    // 等待所有检测完成
    final List<String?> results = await Future.wait(futures);

    // 过滤出可用的WebSocket地址
    final List<String> availableUrls =
        results.where((result) => result != null).cast<String>().toList();

    return availableUrls;
  }

  /// 检测单个WebSocket地址是否可用
  /// [url] 要检测的WebSocket地址
  /// [timeout] 检测超时时间
  /// 返回可用的WebSocket地址，如果不可用则返回null
  static Future<String?> _checkSingleWebSocket(
    String url, {
    required Duration timeout,
  }) async {
    IOWebSocketChannel? channel;
    StreamSubscription? subscription;

    try {
      // 创建WebSocket连接
      channel = IOWebSocketChannel.connect(
        Uri.parse(url),
        connectTimeout: timeout,
      );

      // 创建一个Completer来处理连接结果
      final Completer<bool> completer = Completer<bool>();

      // 监听连接状态
      subscription = channel.stream.listen(
        (message) {
          // 收到任何消息表示连接成功
          if (!completer.isCompleted) {
            completer.complete(true);
          }
        },
        onDone: () {
          // 连接正常关闭也表示连接成功
          if (!completer.isCompleted) {
            completer.complete(true);
          }
        },
        onError: ( error) {
          if (!completer.isCompleted) {
            completer.complete(false);
          }
        },
        cancelOnError: true,
      );


      // 等待连接结果或超时
      final bool isConnected = await completer.future.timeout(
        timeout,
        onTimeout: () => false,
      );

      return isConnected ? url : null;
    } catch (e) {
      // 捕获所有异常（连接错误、超时等），返回null表示不可用
      return null;
    } finally {
      // 清理资源
      try {
        await subscription?.cancel();
        await channel?.sink.close(status.normalClosure);
      } catch (e) {
        // 忽略清理过程中的错误
      }
    }
  }

  /// 简单的WebSocket连接性检测
  /// [url] 要检测的WebSocket地址
  /// [timeout] 检测超时时间，默认5秒
  /// 返回true表示可以连接，false表示无法连接
  static Future<bool> isWebSocketConnectable(
    String url, {
    Duration? timeout,
  }) async {
    final Duration checkTimeout = timeout ?? const Duration(seconds: 5);
    final String? result =
        await _checkSingleWebSocket(url, timeout: checkTimeout);
    return result != null;
  }

  /// 快速检测WebSocket连接（更短的超时时间）
  /// [urls] 需要检测的WebSocket地址列表
  /// [timeout] 超时时间，默认3秒
  /// 返回可用的WebSocket地址列表
  static Future<List<String>> quickCheckWebSockets(
    List<String> urls, {
    Duration? timeout,
  }) async {
    final Duration quickTimeout = timeout ?? const Duration(seconds: 3);
    return await checkAvailableWebSockets(urls, timeout: quickTimeout);
  }

  /// 获取WebSocket连接的详细检测信息
  /// [urls] 需要检测的WebSocket地址列表
  /// [timeout] 检测超时时间
  /// 返回包含检测详情的Map
  static Future<Map<String, dynamic>> getWebSocketCheckDetails(
    List<String> urls, {
    Duration? timeout,
  }) async {
    final Duration checkTimeout = timeout ?? const Duration(seconds: 5);
    final DateTime startTime = DateTime.now();

    final List<String> availableUrls = await checkAvailableWebSockets(
      urls,
      timeout: checkTimeout,
    );

    final DateTime endTime = DateTime.now();
    final Duration totalTime = endTime.difference(startTime);

    return {
      'totalUrls': urls.length,
      'availableUrls': availableUrls,
      'availableCount': availableUrls.length,
      'unavailableCount': urls.length - availableUrls.length,
      'checkDuration': totalTime.inMilliseconds,
      'timeout': checkTimeout.inMilliseconds,
      'successRate': urls.isEmpty ? 0.0 : (availableUrls.length / urls.length),
    };
  }
}
